package com.xjve.framework.hibernate.query.core;

import com.xjve.framework.hibernate.query.exception.SqlQueryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 参数安全检查器
 */
public class ParameterValidator {

    private static final Logger logger = LoggerFactory.getLogger(ParameterValidator.class);

    // SQL注入风险关键词
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
            "(alter|create|delete|drop|exec(ute){0,1}|insert( +into){0,1}|merge|select|update|union( +all){0,1})",
            Pattern.CASE_INSENSITIVE
    );

    // 匹配${}参数占位符
    private static final Pattern PARAMETER_PATTERN = Pattern.compile("\\$\\{([^{}]+)}");

    /**
     * 验证SQL参数
     * @param sql SQL语句
     * @param parameters 参数
     */
    public void validateParameters(String sql, Map<String, Object> parameters) {
        // 检查SQL注入风险
        checkSqlInjectionRisk(sql);

        // 检查参数完整性
        checkParameterCompleteness(sql, parameters);

        // 检查参数类型安全性
        checkParameterTypes(parameters);
    }

    /**
     * 检查SQL注入风险
     * @param sql SQL语句
     */
    private void checkSqlInjectionRisk(String sql) {
        Matcher matcher = SQL_INJECTION_PATTERN.matcher(sql);
        if (matcher.find()) {
            logger.warn("Potential SQL injection risk detected: {}", matcher.group());
            // 在生产环境可以考虑抛出异常或进行更严格的处理
        }
    }

    /**
     * 检查参数完整性
     * @param sql SQL语句
     * @param parameters 参数
     */
    private void checkParameterCompleteness(String sql, Map<String, Object> parameters) {
        Matcher matcher = PARAMETER_PATTERN.matcher(sql);

        while (matcher.find()) {
            String paramName = matcher.group(1).trim();

            // 如果使用了参数占位符但没有提供参数值
            if (parameters == null || !parameters.containsKey(paramName)) {
                throw new SqlQueryException("Missing required parameter: " + paramName);
            }

            // 检查参数值是否为空
            Object value = parameters.get(paramName);
            if (value == null || (value instanceof String && !StringUtils.hasText((String) value))) {
                logger.warn("Parameter {} has empty value", paramName);
            }
        }
    }

    /**
     * 检查参数类型安全性
     * @param parameters 参数
     */
    private void checkParameterTypes(Map<String, Object> parameters) {
        if (parameters == null) {
            return;
        }

        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            String paramName = entry.getKey();
            Object value = entry.getValue();

            // 不允许直接传递集合或数组作为参数值（防止批量注入）
            if (value instanceof Iterable || value.getClass().isArray()) {
                throw new SqlQueryException("Unsupported parameter type for " + paramName +
                        ". Collection or array is not allowed directly.");
            }

            // 不允许传递SQL相关的对象
            if (value instanceof CharSequence && value.toString().contains(";")) {
                logger.warn("Parameter {} contains semicolon, potential SQL injection risk", paramName);
            }
        }
    }
}
